/*
* Copyright (C) Microsoft. All rights reserved.  
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not 
* use this file except in compliance with the License.  You may obtain a copy 
* of the License at http://www.apache.org/licenses/LICENSE-2.0  
* 
* THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED 
* WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, 
* MERCHANTABLITY OR NON-INFRINGEMENT. 
*
* See the Apache License, Version 2.0 for specific language governing 
* permissions and limitations under the License.
*
*/
#include "pch.h"
#include <journal/app/constants.h>
#include <journal/views/scroll_bars.h>

namespace journal { namespace view {

scroll_bars::scroll_bars() : 
    _state(state::out)
{
}

void scroll_bars::setVisibility(const bool visible)
{
    if (_state == state::out)
    {
        if (visible)
        {
            b::float32 t = constants::general::currentTime();
            _progress = 0.f;
            _animationEndTime = t + constants::animations::scrollbarVisibilityDuration();
            _animation = b::linear_interpolation(
                t,
                _animationEndTime,
                _progress,
                1.f
                );

            _state = state::fadingIn;
        }
    }
    else if (_state == state::fadingOut)
    {
        if (visible)
        {
            b::float32 t = constants::general::currentTime();
            _animationEndTime = t + (t - _animation.t0()) ;
            _animation = b::linear_interpolation(
                t,
                _animationEndTime,
                _progress,
                1.f
                );

            _state = state::fadingIn;
        }
    }
    else if (_state == state::fadingIn)
    {
        if (!visible)
        {
            b::float32 t = constants::general::currentTime();
            _animationEndTime = t + (t - _animation.t0());
            _animation = b::linear_interpolation(
                t,
                _animationEndTime,
                _progress,
                0.f
                );

            _state = state::fadingOut;
        }
    }
    else if (_state == state::in)
    {
        if (!visible)
        {
            b::float32 t = constants::general::currentTime();
            _progress = 1.f;
            _animationEndTime = t + constants::animations::scrollbarVisibilityDuration();
            _animation = b::linear_interpolation(
                t,
                _animationEndTime,
                _progress,
                0.f
                );

            _state = state::fadingOut;
        }
    }
}

void scroll_bars::onRender()
{
    // apply state transitions
    if (_state == state::out)
    {
        return;
    }

    if (_state == state::fadingIn || _state == state::fadingOut)
    {
        b::float32 t = constants::general::currentTime();
        _progress = _animation.apply(t);
        if (t >= _animationEndTime)
        {
            _state = ((_state == state::fadingIn) ? state::in : state::out);
        }
    }

    m::rectangle rect;

    // render vertical scroll bar
    if (_dimensions.y < 1.f)
    {
        rect.left = constants::shellService()->windowSize().x - 8;
        rect.right = constants::shellService()->windowSize().x - 1;
        rect.top = _position.y * constants::shellService()->windowSize().y;
        rect.bottom  = rect.top + (_dimensions.y * constants::shellService()->windowSize().y);

        this->renderRect(rect);
    }

    // render horizontal scroll bar
    if (_dimensions.x < 1.f)
    {
        rect.left = _position.x * constants::shellService()->windowSize().x;
        rect.right = rect.left + (_dimensions.x * constants::shellService()->windowSize().x);
        rect.top = constants::shellService()->windowSize().y - 8;
        rect.bottom = constants::shellService()->windowSize().y - 1;

        this->renderRect(rect);
    }
}

void scroll_bars::renderRect(const m::rectangle& rect)
{
    std::shared_ptr<g::iengine> graphics = constants::graphics();

    std::shared_ptr<g::ieffect2> effect;
    effect = graphics->getStandardEffect(g::standard_effect::screenColored);

    g::packed_color c = g::packColor((b::uint32)(_progress * 220), 0, 0, 0);
    graphics->setColor(c);

    graphics->setAlphaBlend(g::enabled_state::enabled);
    graphics->setZBuffer(g::enabled_state::disabled);
    graphics->setCulling(g::cull_state::none);

    effect->begin(graphics);
    graphics->beginScreenSpace(g::primitive_type::triangleStrip);

    m::point4d pos1(rect.left, rect.top, 1.0f);
    graphics->setScreenSpaceVertex(pos1);

    m::point4d pos2(rect.right-1, rect.top, 1.0f);
    graphics->setScreenSpaceVertex(pos2);

    m::point4d pos4(rect.left, rect.bottom-1, 1.0f);
    graphics->setScreenSpaceVertex(pos4);

    m::point4d pos3(rect.right-1, rect.bottom-1, 1.0f);
    graphics->setScreenSpaceVertex(pos3);

    graphics->end();

    effect->end(graphics);
}

void scroll_bars::set(const m::point2d& position, const m::point2d& dimensions)
{
    _position = position;
    _dimensions = dimensions;
}

}} // namespace journal::view